package com.eqdd.yiqidian.http;


import com.eqdd.yiqidian.base.BaseActivity;
import com.eqdd.yiqidian.bean.BaseBean;
import com.eqdd.yiqidian.utils.GsonUtils;
import com.facebook.stetho.okhttp3.StethoInterceptor;
import com.google.gson.Gson;
import com.trello.rxlifecycle.LifecycleProvider;
import com.trello.rxlifecycle.android.ActivityEvent;

import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.RequestBody;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import rx.Observable;
import rx.Observer;
import rx.Subscriber;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Func1;
import rx.schedulers.Schedulers;

/**
 * Created by vzhihao on 2016/11/1.
 */
public class HttpMethods {
    /*
     *所有的请求数据的方法集中地
     * 根据MovieService的定义编写合适的方法
     * 其中observable是获取API数据
     * observableCahce获取缓存数据
     * new EvictDynamicKey(false) false使用缓存  true 加载数据不使用缓存
     */
    //    private static File cacheDirectory = FileUtil.getcacheDirectory();
//    private static final CacheProviders providers = new RxCache.Builder()
//            .persistence(cacheDirectory)
//            .using(CacheProviders.class);
    private static final int DEFAULT_TIMEOUT = 5;
    private static final MediaType textType = MediaType.parse("text/plain");

    private Retrofit retrofit;
    public HttpService httpService;


    //构造方法私有
    private HttpMethods() {
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                .addInterceptor(new LogInterceptor())
                .cookieJar(new CookiesManager())
                .addNetworkInterceptor(new CacheInterceptor())
                .addNetworkInterceptor(new StethoInterceptor())
                .cache(new CacheProvide().provideCache())
                .build();


        retrofit = new Retrofit.Builder()
                .client(okHttpClient)
                .addConverterFactory(StringConverterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .baseUrl(HttpConfig.BASE_URL)
                .build();

        httpService = retrofit.create(HttpService.class);
    }
    public <T> Observable<List<T>> getObserverDataFromServer(BaseActivity life,
                                                             Class<T> clazz, String url,
                                                             Map<String, String> headMaps,
                                                             Map<String, String> map, int mode) {

        Observable<List<T>> listObservable = (mode == 0 ? httpService.getDataFromServer(url, headMaps, map) : httpService.getDataFromServerPost(url, headMaps, map)).flatMap(new Func1<String, Observable<List<T>>>() {
            @Override
            public Observable<List<T>> call(String s) {
                BaseBean<T> baseBean = GsonUtils.changeGsonToBaseBean(s, clazz);
                return Observable.just(baseBean.getItems());
            }
        });
        if (life != null) {
            listObservable=listObservable.compose(life.bindToLifecycle());
        }
        return listObservable
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());

    }


    public <T> Observable<T> getObserverDataFromServerBean(BaseActivity life,
                                                             Class<T> clazz, String url,
                                                             Map<String, String> headMaps,
                                                             Map<String, String> map, int mode) {

        Observable<T> listObservable = (mode == 0 ? httpService.getDataFromServer(url, headMaps, map) : httpService.getDataFromServerPost(url, headMaps, map)).flatMap(new Func1<String, Observable<T>>() {
            @Override
            public Observable<T> call(String s) {
                return Observable.just(clazz == String.class ? (T) s : new Gson().fromJson(s, clazz));
            }
        });
        if (life != null) {
            listObservable=listObservable.compose(life.bindToLifecycle());
        }
        return listObservable
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());

    }

    public <T> Subscription getDataFromServer(LifecycleProvider<ActivityEvent> life, Subscriber<T> subscriber, final Class<T> clazz,
                                              String url, Map<String, String> headMaps, Map<String, String> map, int mode) {
        Observable<T> tObservable = (mode == 0 ? httpService.getDataFromServer(url, headMaps, map) : httpService.getDataFromServerPost(url, headMaps, map)).flatMap(new Func1<String, Observable<T>>() {
            @Override
            public Observable<T> call(String s) {
                return Observable.just(clazz == String.class ? (T) s : new Gson().fromJson(s, clazz));
            }
        });
        if (life == null) {//
            return tObservable
                    .subscribeOn(Schedulers.io())
                    .unsubscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(subscriber);
        } else {
            return tObservable
                    .compose(life.bindToLifecycle())
                    .subscribeOn(Schedulers.io())
                    .unsubscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(subscriber);
        }

    }

    public <T> Subscription getDataFromServerMultipart(LifecycleProvider<ActivityEvent> life, Subscriber<T> subscriber, final Class<T> clazz,
                                                       String url, Map<String, String> headMaps, Map<String, RequestBody> map, Map<String,String> filemap) {

        Observable<T> tObservable = httpService.getDataFromServerMultipart(url, headMaps, map,HttpMultiUtil.prepareFilePart(filemap)).flatMap(new Func1<String, Observable<T>>() {
            @Override
            public Observable<T> call(String s) {
                return Observable.just(clazz == String.class ? (T) s : new Gson().fromJson(s, clazz));
            }
        });
        if (life!=null){
           tObservable=tObservable.compose(life.bindToLifecycle());

        }
        return tObservable
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(subscriber);
    }

    public <T> Observable<T> getObserverDataFromServerMultipart(LifecycleProvider<ActivityEvent> life,final Class<T> clazz,
                                                       String url, Map<String, String> headMaps, Map<String, RequestBody> map, Map<String,String> fileMap) {

        Observable<T> tObservable = httpService.getDataFromServerMultipart(url, headMaps, map, HttpMultiUtil.prepareFilePart(fileMap)).flatMap(new Func1<String, Observable<T>>() {
            @Override
            public Observable<T> call(String s) {
                return Observable.just(clazz == String.class ? (T) s : new Gson().fromJson(s, clazz));
            }
        });
        if (life!=null){
            tObservable=tObservable.compose(life.bindToLifecycle());
        }
        return tObservable
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
    }
    //在访问HttpMethods时创建单例
    private static class SingletonHolder {
        private static final HttpMethods INSTANCE = new HttpMethods();
    }

    //获取单例
    public static HttpMethods getInstance() {
        return SingletonHolder.INSTANCE;
    }


    //拦截固定格式的公共数据类型Response<T>,判断里面的状态码
    private class ServerResponseFunc<T> implements Func1<BaseBean<T>, BaseBean<T>> {
        @Override
        public BaseBean<T> call(BaseBean<T> reponse) {
            //对返回码进行判断，如果不是0，则证明服务器端返回错误信息了，便根据跟服务器约定好的错误码去解析异常
            if (reponse.getStatus() < 0) {
                //如果服务器端有错误信息返回，那么抛出异常，让下面的方法去捕获异常做统一处理
                throw new ServerException();

            }
            //服务器请求数据成功，返回里面的数据实体
            return reponse;
        }
    }

    public class ServerException extends RuntimeException {
        public int code;
        public String message;

    }


    private class HttpResponseFunc<T> implements Func1<Throwable, Observable<T>> {
        @Override
        public Observable<T> call(Throwable throwable) {
//            ExceptionEngine为处理异常的驱动器
            return Observable.error(ExceptionEngine.handleException(throwable));
        }
    }

    /**
     * 插入观察者
     *
     * @param observable
     * @param observer
     * @param <t>
     */
    public static <t> void setSubscribe(Observable<t> observable, Observer<t> observer) {
        Subscription subscribe = observable.subscribeOn(Schedulers.io())
                .subscribeOn(Schedulers.newThread())//子线程访问网络
                .observeOn(AndroidSchedulers.mainThread())//回调到主线程
                .subscribe(observer);
    }

}